package com.cskaoyan.javase.oop1._11block._2building;

/**
 * @description: 构造代码块
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 构造代码块: 指的是声明在成员位置的一种代码块
 * 语法结构: {}
 * 构造代码块的作用: 随着构造器的执行的而执行,可以在创建对象的过程中,给成员变量赋值
 *
 * 总结一下目前学习的给(普通)成员变量赋值的方式:
 *  a,创建对象过程中赋值的方式:
 *      1,默认初始化,具有默认值
 *      2,显式赋值
 *      3,构造代码块
 *      4,构造器
 *  b,对象创建出来以后的赋值方式:
 *      1,对象名点访问然后赋值
 *      2,对象名点调用方法去赋值
 *
 * 现在重点研究创建对象过程中,成员变量的赋值方式,遵循"掐头去尾"的原则:
 *      1,默认初始化是第一步
 *      2,构造器是最后一步
 *      3,通过代码验证,构造代码块和成员变量的显式赋值谁在代码书写的上面,谁就先执行,在代码书写下面的后执行
 *
 * 我们观察到构造代码是可以写在成员变量声明的上面的,这样的形式看起来很古怪,因为成员变量还没有声明却进行了赋值
 * 在这个过程当中,编译器为我们完成了一些事情,通过查看反编译class文件,我们发现:
 *      1,编译后的代码不存在构造代码块的结构
 *      2,编译过程中,编译器会智能把显式赋值和构造代码块中代码放入构造器
 *          目的是为了保证显式赋值和构造代码块按照代码的书写顺序去执行(谁在代码书写的上面,谁先执行)
 *
 * 最后,我们来总结一下构造代码块:
 *      构造代码块中的代码会在编译后,智能的放入构造方法中,并且是每一个构造方法
 *
 *
 * new对象过程，构造代码块的执行顺序
 * - 对象创建出来后，就把所有成员变量的值默认初始化，然后开始其余赋值操作
 * - 如果构造器在第一行显式的调用了另一个构造器，那么程序先跳转到this构造器，但并不会执行
 * - 而是
 *   - 按照类中定义代码块和成员变量的位置，从上到下执行代码块和成员变量自身的初始化语句
 * - 继而执行该this构造器代码
 * - 最后执行该构造器代码
 *
 * 构造代码块的一些常见用途:
 *   构造代码块中的代码会自动加入构造器,所以我们可以"提取公因式",把每个构造器都需要执行的语句放进构造代码块当中
 *
 *
 * 注意事项:
 *  - 应该永远将构造代码块，放在成员变量的定义语句下面
 *   - 一方面，如果代码块初始化在上，成员变量声明在下，逻辑上会很奇怪
 *   - 另一方面，如果对象的创建依赖于代码块和成员变量的定义位置，很容易引发错误
 * - 可以使用this关键字，但是意义不大
 *
 *
 */
public class Demo {
    public static void main(String[] args) {
        /*Student s = _1new Student(38);
        System.out.println(s.age); //38*/

        /*Student s = _1new Student();
        //System.out.println(s.age); //28

        Student s2 = _1new Student(18);*/

        System.out.println(Student.name);
        Student s = new Student();
        System.out.println(Student.name);
    }
}

class Student {

    //声明一个静态成员变量
    static String name;
    {
        //思考: 构造代码块能否成静态成员变量赋值?
        //可以赋值,但是这种赋值想要生效,必须依赖于创建对象,执行构造方法, 所以这种方式不太合适
        Student.name = "马三";
    }

    int age = 18;
    //构造代码块
    //构造代码块中可以使用this关键字,用来访问该类的成员变量和方法
    /*{
        System.out.println("我创建了一个Student");
        age = 28;
    }*/

    public Student() {
    }

    public Student(int age) {
        this.age = age;
    }

    public void test(){}
}
